#include "StdAfx.h"
#include "SubroutinePopulation.h"
EvaluatingTermSet* SubroutinePopulation::BlockPopulation(  EvaluatingTermSet* TS){
		static  EvaluatingTermSet* BP = NULL;
		if(TS) BP = TS;
		return BP;
	}
vector<const Token*>* SubroutinePopulation::StemCells (vector<const Token*>* Vec){
	static vector<const Token*>* VVILT = NULL;
	if(Vec) VVILT = Vec;
	return VVILT;
	}

const Type* SubroutinePopulation::GoalType (const Type* Ty){
	static const Type* GT = NULL;
	if(Ty) GT = Ty;
	return GT;
	}
Token::pointer SubroutinePopulation::Method_2_1(const Token& Ter){
	if(Ter.isType( ))	return NULL;
	const Term* Te = BlockPopulation( )->getRandFunctionInDomain(_TERM(Ter).getType());
	if(!Te) return NULL;	
	ApplicationTerm* NewTerm = new ApplicationTerm(*Te, Ter);		
	Term::pointer ToBeInserted = NewTerm->normalized();
	ToBeInserted->setSyntax(NewTerm->toString());
	delete NewTerm;
	return ToBeInserted;
	}

Token::pointer SubroutinePopulation::Method_2_2(const Token& Ter){
	if(Ter.isType( )) return NULL;
	TokenSet*			FV = TokenSet::freeVariablesof(_TERM(Ter));
	const Token*		To = FV->getRandToken( );
	Term::pointer		Res = NULL;
	if(To) Res = AbstractTerm(_TERM(Ter), _TERM(*To)).normalized( );
	delete FV;
	return Res;
	}	
Token::pointer SubroutinePopulation::Method_2_3(const Token& Ter){
	if(Ter.isType( )) return NULL;
	if(!(_TERM(Ter).getType( ).isArrowType( ))) return NULL;
	const Term* Ptr =  BlockPopulation( )->getRandTermOfType(_ARROWTYPE(_TERM(Ter).getType( )).getLeft( ));
	Token::pointer Res = NULL;
	if(Ptr){
		 ApplicationTerm Temp(_TERM(Ter), *Ptr);  
		 Res = Temp.normalized();
		}
	return Res;
	}	
Token::pointer SubroutinePopulation::Method_2_4(const Token& Ter){
	if(Ter.isType( )) return NULL;
   	if(!(_TERM(Ter).getType( ).isArrowType( ))) return NULL;
	Term::pointer Temp1 = AbstractTerm::curry(_TERM(Ter));
	Term::pointer Temp2 = Temp1->normalized( ); 
	delete Temp1;
	return Temp2;
}
Token::pointer SubroutinePopulation::Method_2_5(const Token& Ter){
	if(Ter.isType( )) return NULL;	
	TokenSet* FTV = TokenSet::allFreeAtomicTypesof(Ter);
	TokenSet* AT = new TokenSet( );
	for(size_t i=0; i<FTV->size( ); i++)
		if(!(_TERM(Ter).TypeOccursinFreeVariable(_TYPE(FTV->operator [](i)))))
			AT->insert(FTV->operator [](i));

	delete FTV;
	Token::pointer Res = NULL;	
	if(AT->size( ) > 0){
		const Token* To = AT->getRandToken( );
		Res = AbstractTypeTerm(_TERM(Ter), _ATOMICTYPE(*To)).normalized( );
		}
	delete AT;
	return Res;
	}
Token::pointer SubroutinePopulation::Method_2_6(const Token& Ter){
	if(Ter.isType( )) return NULL;
	if(_TERM(Ter).getType( ).isAbstractType( )){
		const Type* Ptr =  SubroutinePopulation::BlockPopulation( )->getRandType( );	
		return ApplicationTerm(_TERM(Ter), *Ptr).normalized( );
		}
	return NULL;
	}
Token::pointer SubroutinePopulation::Method_3_3(const Token& Ty){
	if(Ty.isTerm( )) return NULL;
	if(!(_TYPE(Ty).isAbstractType( ))) return NULL;
	const Type* Ptr = SubroutinePopulation::BlockPopulation( )->getRandType( );	
	return Ty.applyArgument(*Ptr);
	}

Token::pointer SubroutinePopulation::Method_3_4(const Token& Ty){
	if(Ty.isTerm( )) return NULL;
	const Type* Ptr = SubroutinePopulation::BlockPopulation( )->getRandType( );	
	if(Ptr->isAbstractType( ))
		return Ptr->applyArgument(Ty);
	return NULL;
	}

vector< Token::pointer (*) (const Token&)>* SubroutinePopulation::getAllFormationRules( ){
	vector< Token::pointer (*) (const Token&)>* FormationRules = 
										new vector<Token::pointer (*) (const Token&)>( );
	FormationRules->push_back(&(SubroutinePopulation::Method_2_1));
	FormationRules->push_back(&(SubroutinePopulation::Method_2_2));
	FormationRules->push_back(&(SubroutinePopulation::Method_2_3));
	FormationRules->push_back(&(SubroutinePopulation::Method_2_4));
	FormationRules->push_back(&(SubroutinePopulation::Method_2_5));
	FormationRules->push_back(&(SubroutinePopulation::Method_2_6));
	FormationRules->push_back(&(SubroutinePopulation::Method_3_3));
	FormationRules->push_back(&(SubroutinePopulation::Method_3_4));
	return FormationRules;
	}
Token::pointer SubroutinePopulation::createNewBlock( vector< Token::pointer (*) (const Token&)>*  Generators){
	Token::const_reference To = *(SubroutinePopulation::BlockPopulation( )->getRandToken( ));
	size_t theoremIndex = rand( ) % Generators->size( );
	return (*(Generators->operator [](theoremIndex)))( To );
	return NULL;
}		



Token::const_reference SubroutinePopulation::BlockPopulationGenerator(
	vector< Token::pointer (*) (const Token&)>*  Generators, 
	bool (*QAccept)( Token::const_reference )){

	const Token* Res = NULL;
	while(!Res){
		Token::pointer NewInd = SubroutinePopulation::createNewBlock( Generators );
		if(NewInd){
			/*if(QAccept){
				if(!((*QAccept)( *NewInd ))){
					delete NewInd;
					NewInd = NULL;
					continue;
					}
				}	*/  
			Res = SubroutinePopulation::BlockPopulation( )->insert(*NewInd);
			delete NewInd;
			NewInd = NULL;
			}
		}	 
		return *Res;
	}



VirtualInvertedListTerm* SubroutinePopulation::CDNAStatementPopulationGenerator(  ){
	//Trying to create a randomly constructed element of CDNAStatementPopulation
	//Pick some random stem cell. It will be the base on which to construct
	//the new individual
	size_t StemChoiceNumber = SubroutinePopulation::StemCells( )->size( );
	VirtualInvertedListTerm* Ind = NULL;
	while((!Ind)||(!(Ind->getType( ) == *SubroutinePopulation::GoalType( )))){
		if(!Ind){
			Ind = new VirtualInvertedListTerm(_TERM(*(SubroutinePopulation::StemCells( )->operator[ ](rand( )%StemChoiceNumber))));
			continue;
			}
		if((Ind->getType( ).isAtomicType( )) || ( Ind->size( ) > 6 )){
			delete Ind;
			Ind = NULL;
			continue;
			}
		if(Ind->getType( ).isArrowType( )) {
			const Term* Ter = SubroutinePopulation::BlockPopulation( )->getRandTermOfType(_ARROWTYPE(Ind->getType( )).getLeft( ));
			if(Ter){
				Ind->push_back(*Ter);
				}
			else{
				delete Ind;
				Ind = NULL	;
				}
			continue;
			}
		if(Ind->getType( ).isAbstractType( )){
			const Type* Ter = SubroutinePopulation::BlockPopulation( )->getRandType( );
			while(Ter->isAbstractType( ) && Ter->complexity( ) >= Ind->getType( ).complexity( )) Ter = SubroutinePopulation::BlockPopulation( )->getRandType( );
			Ind->push_back( *Ter );
			continue;
			}
		}

	return Ind;
	}

Individual SubroutinePopulation::CDNAStatementSpawnerWithoutSideEffect(const Individual Dad, const Individual Mom, Individual Child, size_t start){
	bool includesType = false;
	string DebDad(Dad->toString( ));
	string DebMom(Mom->toString( ));
	string Deb1(Child->toString( ));
	const Individual GeneGiver = ((rand( )%2)?Dad:Mom);
	while(start < GeneGiver->size( )){
		Child->push_back((*GeneGiver)[start]);
		if((*GeneGiver)[start].isType( )) includesType = true;
	    if(!includesType) GeneGiver = ((rand( )%2)?Dad:Mom);
		start++;	 
		string Deb2(Child->toString( ));
		}
	string Deb3(Child->toString( ));
	return Child;
	}	
Individual SubroutinePopulation::CDNAStatementSpawnerWithSideEffect(const Individual Dad, const Individual Mom){
	size_t start = 1;	
	Token* NewBlockRaw = ((rand( )%2)?(*Mom)[0].clone( ):(*Dad)[0].clone( ));
	
	while   ((start < Mom->size( ) && start < Dad->size( ))		  
				&&
				((*Mom)[start] == (*Dad)[start])) 
				start++;
	
	for(size_t i = 1; i < start; i++){
		Token* Temp =   NewBlockRaw;
		NewBlockRaw = NewBlockRaw->applyArgument( (*Mom)[i] );
		delete Temp;
		}  

	TokenSet*			FV = TokenSet::freeVariablesof(_TERM(*NewBlockRaw));
	const Token*		To = FV->getRandToken( );
	string str1(NewBlockRaw->toString( ));
	Individual Child = NULL;
	
	if(To) {
		Term* NewBlock = AbstractTerm(_TERM(*NewBlockRaw), _TERM(*To)).normalized( ); 	
		string str2(NewBlock->toString( ));
		const Token* Tok0 = SubroutinePopulation::BlockPopulation( )->find(*NewBlock);
		if(!Tok0) {
			size_t TotalComplexity = 0;
			for(size_t i=0; i<BlockPopulation( )->size( );i++)
				TotalComplexity += BlockPopulation( )->operator[ ](i).complexity( );
			

			Tok0 =  SubroutinePopulation::BlockPopulation( )->insert(*NewBlock);}   
		delete NewBlock;
		const Token* Tok1 = SubroutinePopulation::BlockPopulation( )->find(*To);
		Child = new VirtualInvertedListTerm(_TERM(*Tok0));
		Child->push_back( *Tok1 );
		CDNAStatementSpawnerWithoutSideEffect(Dad, Mom, Child, start);
		}	
	delete FV;
	delete NewBlockRaw;
	return Child;
	}

Individual SubroutinePopulation::CDNAStatementSpawner(const Individual Dad, const Individual Mom){
	Individual Child = NULL;
	size_t index = 0;
	while   ((index < Mom->size( ) && index < Dad->size( ))		  
				&&
				((*Mom)[index] == (*Dad)[index])) 
				index++;

	if((index > 0)||((Dad->size( ) == 1)&&(Mom->size( ) == 1))){
		return  CDNAStatementSpawnerWithSideEffect(Dad, Mom);
		}
	else{
		const Token& To = ((rand( )%2)?(*Dad)[index]:(*Mom)[index]);
		Child = new VirtualInvertedListTerm( _TERM(To)); 
		CDNAStatementSpawnerWithoutSideEffect( Dad, Mom, Child, 1);
		}
	  return Child;
	}

void SubroutinePopulation::CDNAStatementMutator( Individual Ind){
	size_t mutIndex = rand( )%Ind->size( );	
	if((*Ind)[mutIndex].isTerm( )){
		const Term* NewBlock = BlockPopulation( )->getRandTermOfType( _TERM((*Ind)[mutIndex]).getType( ));	
		if(NewBlock){
			Ind->replaceElt(NewBlock, mutIndex);
			}
		}
}









 
 